﻿using System;

namespace IrcDotNetConsole
{
    static class Program
    {
        static IrcDotNet.Service.Server myServer { get; set; }

        static void Main(string[] args)
        {
            myServer = new IrcDotNet.Service.Server();

            string line;
            System.Collections.Generic.List<String> parts = new System.Collections.Generic.List<string>();
            string command;

            while (true)
            {
                if (!myServer.IsConnected) Console.Write("> ");
                else if (!myServer.Channel.IsConnected) Console.Write("-> ");
                else Console.Write("--> ");
                line = Console.ReadLine();

                if (line == null || line.Length < 1) continue;
                if (line.StartsWith("/"))
                {
                    parts.Clear();
                    parts.AddRange(line.Split(' '));
                    command = parts[0];
                    parts.RemoveAt(0);

                    switch (command)
                    {
                        case "/exit":
                            Environment.Exit(0);
                            break;

                        case "/connect":
                            if (parts.Count > 0) Connect(parts[0]);
                            else Console.WriteLine("=> You must define the server to connect. <=");
                            break;

                        case "/disconnect":
                            if (parts.Count > 0) Disconnect(String.Join(" ", parts));
                            else Console.WriteLine("=> You must define the comment. <=");
                            break;

                        case "/join":
                            if (parts.Count > 0) Join(parts[0]);
                            else Console.WriteLine("=> You must define the channel to join. <=");
                            break;

                        case "/leave":
                            if (parts.Count > 0) Leave(String.Join(" ", parts));
                            else Console.WriteLine("=> You must define the comment. <=");
                            break;

                        case "/msg":
                            if (parts.Count > 1) Whisp(parts);
                            else Console.WriteLine("=> You must define the user and the message. <=");
                            break;

                        case "/list":
                            ListUser();
                            break;

                        default:
                            Console.WriteLine("=> Command not recognized. <=");
                            break;
                    }
                }
                else Say(line);
            }
        }

        static void Connect(string serverAddress)
        {
            if (myServer.IsConnected)
            {
                Console.WriteLine("=> Cannot connect: you are already connected to {0}. <=",
                        myServer.Name);
                return;
            }

            try
            {
                Console.WriteLine("=> Connecting to {0}... <=", serverAddress);

                if (myServer.Connect(serverAddress,
                    "TestUser", "TestUser", "User for test purpose"))
                {
                    Console.WriteLine("=> Connected to {0}. <=", serverAddress);
                }
                else
                {
                    Console.WriteLine("=> Connection to {0} timed out. <=", serverAddress);
                }
            }
            catch (Exception)
            {
                Console.WriteLine("=> Error on connection to {0}. <=", serverAddress);
            }
        }

        static void Disconnect(string comment)
        {
            if (!myServer.IsConnected)
            {
                Console.WriteLine("=> Cannot disconnect: you are not connected. <=");
                return;
            }

            Console.WriteLine("=> Disconnecting from {0}... <=", myServer.Name);

            if (myServer.Disconnect(comment))
            {
                Console.WriteLine("=> Disconnected from {0}. <=", myServer.Name);
            }
            else
            {
                Console.WriteLine("=> Disconnection from {0} timed out. <=", myServer.Name);
            }
        }

        static void Join(string channelName)
        {
            if (!myServer.IsConnected)
            {
                Console.WriteLine("=> Cannot join: you are not connected. <=");
                return;
            }

            if (myServer.Channel.IsConnected)
            {
                Console.WriteLine("=> Cannot join: you are already on {0} channel. <=",
                    myServer.Channel.Name);
                return;
            }

            Console.WriteLine("=> Join {0}... <=", channelName);

            if (myServer.Channel.Join(channelName))
            {
                Console.WriteLine("=> {0} joined. <=", channelName);
                myServer.Channel.Messages.CollectionChanged += messageReceived;
            }
            else
            {
                Console.WriteLine("=> Join to {0} timed out. <=", channelName);
            }
        }

        static void Leave(string comment)
        {
            if (!myServer.IsConnected)
            {
                Console.WriteLine("=> Cannot leave: you are not connected. <=");
                return;
            }

            if (!myServer.Channel.IsConnected)
            {
                Console.WriteLine("=> Cannot leave: you are not on a channel. <=");
                return;
            }

            Console.WriteLine("=> Leaving {0}... <=", myServer.Channel.Name);

            if (myServer.Channel.Leave(comment))
            {
                Console.WriteLine( "=> {0} left. <=", myServer.Channel.Name);
            }
            else
            {
                Console.WriteLine("=> Leave from {0} timed out. <=", myServer.Channel.Name);
            }
        }

        static void Say(string message)
        {
            if (!myServer.IsConnected || myServer.Channel == null || !myServer.Channel.IsConnected)
            {
                Console.WriteLine("=> You need to be connected to a channel for send a message. <=");
                return;
            }

            myServer.Channel.Say(message);
        }

        static void Whisp(System.Collections.Generic.List<string> parts)
        {
            if (!myServer.IsConnected)
            {
                Console.WriteLine("=> You need to be connected to a server for send a private message. <=");
                return;
            }

            string user = parts[0];
            parts.RemoveAt(0);

            myServer.Whisp(user, string.Join(" ", parts));
        }

        static void ListUser()
        {
            if (!myServer.IsConnected)
            {
                Console.WriteLine("=> You need to be connected to a server for list users. <=");
                return;
            }

            if (!myServer.Channel.IsConnected)
            {
                Console.Write("=> Users in the {0} server: ", myServer.Name);
                foreach (string user in myServer.ListUser())
                {
                    Console.Write(user + " ");
                }
                Console.WriteLine("<=");
            }
            else
            {
                Console.Write("=> Users in the {0} channel: ", myServer.Channel.Name);
                foreach (string user in myServer.Channel.ListUser())
                {
                    Console.Write(user + " ");
                }
                Console.WriteLine("<=");
            }
        }

        static void messageReceived(object s, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            foreach (Tuple<string, string> newItem in e.NewItems)
            {
                Console.Write("{ [{0:t}] <{1}> {2} }", DateTime.Now, newItem.Item1, newItem.Item2);
            }
        }
    }
}
